#include "service_logger_impl.hh"
#include "../box/service_box.hh"

kratos::service::ServiceLoggerImpl::ServiceLoggerImpl(
    const std::string &name, kratos::service::ServiceBox *box) {
  name_ = "[" + name + "]";
  box_ = box;
}

kratos::service::ServiceLoggerImpl::~ServiceLoggerImpl() {}

auto kratos::service::ServiceLoggerImpl::batch_log_begin(int log_level)
    -> void {
  if (!stream_empty()) {
    batch_log_end();
  }
  batch_level_ = log_level;
}

auto kratos::service::ServiceLoggerImpl::batch_log_end() -> void {
  box_->write_log_line(batch_level_, name_ + ss_.str());
  ss_.str("");
  batch_level_ = 0;
}

auto kratos::service::ServiceLoggerImpl::verbose_log(const std::string &log)
    -> void {
  if (!stream_empty()) {
    batch_log_end();
  }
  box_->write_log_line(klogger::Logger::VERBOSE, name_ + log);
}

auto kratos::service::ServiceLoggerImpl::info_log(const std::string &log)
    -> void {
  if (!stream_empty()) {
    batch_log_end();
  }
  box_->write_log_line(klogger::Logger::INFORMATION, name_ + log);
}

auto kratos::service::ServiceLoggerImpl::debug_log(const std::string &log)
    -> void {
  if (!stream_empty()) {
    batch_log_end();
  }
  box_->write_log_line(klogger::Logger::DIAGNOSE, name_ + log);
}

auto kratos::service::ServiceLoggerImpl::warn_log(const std::string &log)
    -> void {
  if (!stream_empty()) {
    batch_log_end();
  }
  box_->write_log_line(klogger::Logger::WARNING, name_ + log);
}

auto kratos::service::ServiceLoggerImpl::except_log(const std::string &log)
    -> void {
  if (!stream_empty()) {
    batch_log_end();
  }
  box_->write_log_line(klogger::Logger::EXCEPTION, name_ + log);
}

auto kratos::service::ServiceLoggerImpl::fail_log(const std::string &log)
    -> void {
  if (!stream_empty()) {
    batch_log_end();
  }
  box_->write_log_line(klogger::Logger::FAILURE, name_ + log);
}

auto kratos::service::ServiceLoggerImpl::fatal_log(const std::string &log)
    -> void {
  if (!stream_empty()) {
    batch_log_end();
  }
  box_->write_log_line(klogger::Logger::FATAL, name_ + log);
}

auto kratos::service::ServiceLoggerImpl::verbose() -> ServiceLogger & {
  if (!stream_empty()) {
    batch_log_end();
  }
  batch_log_begin(klogger::Logger::VERBOSE);
  return *this;
}

auto kratos::service::ServiceLoggerImpl::info() -> ServiceLogger & {
  if (!stream_empty()) {
    batch_log_end();
  }
  batch_log_begin(klogger::Logger::INFORMATION);
  return *this;
}

auto kratos::service::ServiceLoggerImpl::debug() -> ServiceLogger & {
  if (!stream_empty()) {
    batch_log_end();
  }
  batch_log_begin(klogger::Logger::DIAGNOSE);
  return *this;
}

auto kratos::service::ServiceLoggerImpl::warn() -> ServiceLogger & {
  if (!stream_empty()) {
    batch_log_end();
  }
  batch_log_begin(klogger::Logger::WARNING);
  return *this;
}

auto kratos::service::ServiceLoggerImpl::except() -> ServiceLogger & {
  if (!stream_empty()) {
    batch_log_end();
  }
  batch_log_begin(klogger::Logger::EXCEPTION);
  return *this;
}

auto kratos::service::ServiceLoggerImpl::fail() -> ServiceLogger & {
  if (!stream_empty()) {
    batch_log_end();
  }
  batch_log_begin(klogger::Logger::FAILURE);
  return *this;
}

auto kratos::service::ServiceLoggerImpl::fatal() -> ServiceLogger & {
  if (!stream_empty()) {
    batch_log_end();
  }
  batch_log_begin(klogger::Logger::FATAL);
  return *this;
}

auto kratos::service::ServiceLoggerImpl::operator<<(const char *str)
    -> ServiceLogger & {
  ss_ << str;
  return *this;
}

auto kratos::service::ServiceLoggerImpl::operator<<(const std::string &str)
    -> ServiceLogger & {
  ss_ << str;
  return *this;
}

auto kratos::service::ServiceLoggerImpl::operator<<(std::string &&str)
    -> ServiceLogger & {
  ss_ << str;
  return *this;
}

auto kratos::service::ServiceLoggerImpl::operator<<(std::int8_t i8)
    -> ServiceLogger & {
  ss_ << i8;
  return *this;
}

auto kratos::service::ServiceLoggerImpl::operator<<(std::uint8_t ui8)
    -> ServiceLogger & {
  ss_ << ui8;
  return *this;
}

auto kratos::service::ServiceLoggerImpl::operator<<(std::int16_t i16)
    -> ServiceLogger & {
  ss_ << i16;
  return *this;
}

auto kratos::service::ServiceLoggerImpl::operator<<(std::uint16_t ui16)
    -> ServiceLogger & {
  ss_ << ui16;
  return *this;
}

auto kratos::service::ServiceLoggerImpl::operator<<(std::int32_t i32)
    -> ServiceLogger & {
  ss_ << i32;
  return *this;
}

auto kratos::service::ServiceLoggerImpl::operator<<(std::uint32_t ui32)
    -> ServiceLogger & {
  ss_ << ui32;
  return *this;
}

auto kratos::service::ServiceLoggerImpl::operator<<(std::int64_t i64)
    -> ServiceLogger & {
  ss_ << i64;
  return *this;
}

auto kratos::service::ServiceLoggerImpl::operator<<(std::uint64_t ui64)
    -> ServiceLogger & {
  ss_ << ui64;
  return *this;
}

auto kratos::service::ServiceLoggerImpl::operator<<(float f)
    -> ServiceLogger & {
  ss_ << f;
  return *this;
}

auto kratos::service::ServiceLoggerImpl::operator<<(double d)
    -> ServiceLogger & {
  ss_ << d;
  return *this;
}

auto kratos::service::ServiceLoggerImpl::operator<<(const EndLog &)
    -> ServiceLogger & {
  batch_log_end();
  return *this;
}

auto kratos::service::ServiceLoggerImpl::get_stream() -> std::ostream & {
  return ss_;
}

auto kratos::service::ServiceLoggerImpl::stream_empty() -> bool {
  ss_.seekg(0, std::ios::end);
  return (ss_.tellg() > 0);
}

auto kratos::service::ServiceLoggerImpl::get_box() -> ServiceBox* {
  return box_;
}
